#include <string>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <bitset>

using namespace std;

const string str_help = "-h";
const string str_file = "-f";
const string str_mode = "-m";
const string str_word = "-v";

const string str_count_mode = "words";
const string str_checksum_mode = "checksum";
const string str_help_mode = "help";
const string str_error_mode = "error";

class Test {
   public:   
      // чтение файла filename и подсчет количества слов pattern в нём
      void print_count(const string& filename, const string& pattern) {
         ifstream file(filename.c_str());
         int count = 0;
         if (file.is_open()) {
            string line;
            while (file.good()) {
               try {
                  getline(file, line);
                  size_t pos = 0;
                  while (1) {
                     pos = line.find(pattern, pos);
                     if (pos != string::npos) {
                        count++;
                        pos += pattern.size();
                     }
                     else
                        break;
                  }
               } catch (...) {
                  cout << "Возникла проблема при чтении файла '" << filename << "'!\n";
                  break;
               }
            }
            cout << "\n\nКоличество слов '" << pattern << "' в файле '" << filename << "' = " << count << "\n\n";
            file.close();
         } else
            cout << "Не удалось открыть файл " << filename << "!\nВозможно он занят или не существует.\n";
      }
      // подсчет контрольной суммы файла filename
      void print_checksum(string filename) {
         ifstream file(filename.c_str(), ios::in | ios::binary);
         if (file.is_open()) {
            unsigned long cell = 0, checksum = 0;
            while (file.good()) {
               try {
                  cell = 0;
                  file.read((char*)&cell, 4);
                  checksum += cell;
//                  cout << (char*)&cell << "\t" << cell <<endl;
               } catch (...) {
                  cout << "Возникла проблема при чтении файла '" << filename << "'!\n";
                  checksum = 0;
                  break;
               }
            }
            bitset<32> bits(checksum);
            cout << "\n\n32-хбитная чексумма файла '" << filename << "' = " << checksum << "\n"
                 << "В двоичном виде = " << setw(32) << bits << "\n\n";
            file.close();
         } else
            cout << "Не удалось открыть файл " << filename << "!\nВозможно он занят или не существует.\n";
      }
      // вывод справки об использовании программы
      void print_help(const string& prg_name) {
         cout << "Программа, принимающая на вход имя файла и набор параметров.\n" 
              << "В зависимости от параметров программа работает в трёх режимах:\n"
              << "1) " << prg_name << " -f Test.tst -m words -v mother\n"
              << "печатает количество слов 'mother' в файле 'Test.tst'\n\n"
              << "2) " << prg_name << " -f Test.tst -m checksum\n"
              << "печатает 32-хбитную чексумму, рассчитанную по алгоритму \n"
              << "checksum = word1 + word2 + … + wordN \n"
              << "(word1..wordN – 32-хбитные слова, представляющие содержимое файла)\n\n"
              << "3) " << prg_name << " -h\n"
              << "печатает информацию о программе и описание параметров.\n";
      }
};

int main(int argc, char* argv[]) {
   Test test = Test();
   string filename, mode, pattern, message;
   for (int i = 1; i < argc; i++) {
//       cout << i << "." << argv[i] << "\n";
      if (str_help.compare((string)argv[i]) == 0) {
         mode = str_help_mode;
         break;
      } else if (str_file.compare((string)argv[i]) == 0) {
         if (i+1 < argc) {
            i++;
            filename = argv[i];
         } else {
            message += "После ключа '" + str_file + "' должно следовать имя файла!\n";
            mode = str_error_mode;
            break;
         }
      } else if (str_mode.compare((string)argv[i]) == 0) {
         if (i+1 < argc) {
            i++;
            mode = argv[i];
         } else {
            message += "После ключа '" + str_mode + "' должен следовать режим!";
            mode = str_error_mode;
            break;
         }
      } else if (str_word.compare((string)argv[i]) == 0) {
         if (i+1 < argc) {
            i++;
            pattern = argv[i];
         } else {
            message += "После ключа '" + str_word + "' должно следовать слово для поиска!";
            mode = str_error_mode;
            break;
         }
      }
   }
   if (mode.compare(str_count_mode) == 0) {
      if (!pattern.empty())
         test.print_count(filename, pattern);
      else
         cout << "Нельзя посчитать количество слов в файле, т.к. не указано слово для поиска!";
   }
   else if (mode.compare(str_checksum_mode) == 0)
      test.print_checksum(filename);
   else if (mode.compare(str_help_mode) == 0)
      test.print_help(argv[0]);
   else {
      if (!message.empty())
         cout << message;
      else
         cout << "Некорректно указан режим работы программы!\n"
              << "Режим = " << (mode.empty()?"<пусто>":mode);
      cout << + "\nВыполнение программы остановлено.\n\n";
   }
}
